<template>
  <div class="fx-date-picker" ref="datePickerDom">
    <fx-input :model-value="datePickerInput" readonly suffix-icon="icon-date"
              @focus="datePickerShow=true"/>
    <transition @enter="handleAnimationBefore" @after-enter="handleAnimationAfter" @leave="handleAnimationLeave">
      <fx-date v-model:date="datePickerInput" v-if="datePickerShow" ref="dateDom" :dateType="type"
               @close="datePickerShow=false"/>
    </transition>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, ref, watch } from 'vue'
import fxDate from './date.vue'
import { addClassName, dateFormat, prefixStyle, removeClassName } from '@/base/utils'
import { getZIndex, useClickBlank, useModelWatch } from '@/base/hooks'

interface DatePickerProps {
  modelValue: string | Date;
  type: 'day' | 'week' | 'month' | 'year';
}

const Transform = prefixStyle('transform') as number
const Transition = prefixStyle('transition') as number
export default defineComponent({
  name: 'fxDatePicker',
  components: {
    fxDate
  },
  props: {
    modelValue: {
      type: [String, Date] as PropType<string | Date>,
      default: ''
    },
    type: {
      type: String as PropType<'day' | 'week' | 'month' | 'year'>,
      default: 'day'
    }
  },
  setup (props: DatePickerProps) {
    // 日期选择器DOM
    const datePickerDom = ref<HTMLElement>()
    // 日期DOM
    const dateDom = ref()
    // 当前输入内容
    const datePickerInput = ref(dateFormat(props.type, props.modelValue))
    // 日期选择器显示
    const datePickerShow = ref<boolean>(false)

    useModelWatch(() => props.modelValue, datePickerInput)
    useClickBlank(datePickerDom, datePickerShow)

    watch(datePickerShow, (val: boolean) => {
      if (val) {
        document.addEventListener('scroll', handleDatePosition, true)
      } else {
        document.removeEventListener('scroll', handleDatePosition, true)
      }
    })

    const handleAnimationBefore = (el: HTMLElement) => {
      if (!datePickerDom.value) return
      el.style[Transform] = 'scaleY(0)'
      el.style[Transition] = 'all 0.15s'
      el.style.zIndex = String(getZIndex())
      const rect = datePickerDom.value?.getBoundingClientRect()
      let top = rect.top + rect.height + 10
      top = (top + el.clientHeight) <= innerHeight ? top : (rect.top - el.clientHeight - 10)
      const overflowBottom = (top + el.clientHeight) > innerHeight || top < 0
      addClassName(el, overflowBottom ? 'to-top' : 'to-bottom')
    }

    const handleAnimationAfter = (el: HTMLElement) => {
      if (!datePickerDom.value) return
      const rect = datePickerDom.value?.getBoundingClientRect()
      let left = rect.left + rect.width / 2 - el.clientWidth / 2
      left = left < 0 ? 0 : (left + rect.left > innerWidth) ? innerWidth - rect.width : left
      let top = rect.top + rect.height + 10
      top = (top + el.clientHeight) <= innerHeight ? top : (rect.top - el.clientHeight - 10)
      el.style.left = `${left}px`
      el.style.top = `${top}px`
      el.style[Transform] = 'scaleY(1)'
    }

    const handleAnimationLeave = (el: HTMLElement) => {
      el.style[Transition] = 'all 0.15s'
      el.style[Transform] = 'scaleY(0)'
      removeClassName(el, ['to-top', 'to-bottom'])
    }

    const handleDatePosition = () => {
      if (!dateDom.value || !datePickerDom.value) return
      const el = dateDom.value.$el
      const rect = datePickerDom.value?.getBoundingClientRect()
      let top = rect.top + rect.height + 10
      let left = rect.left + rect.width / 2 - el.clientWidth / 2
      left = left < 0 ? 0 : (left + rect.left > innerWidth) ? innerWidth - rect.width : left
      top = (top + el.clientHeight) <= innerHeight ? top : (rect.top - el.clientHeight - 10)
      const overflowBottom = (top + el.clientHeight) > innerHeight || top < 0
      removeClassName(el, ['to-top', 'to-bottom'])
      addClassName(el, overflowBottom ? 'to-top' : 'to-bottom')
      el.style[Transition] = 'none'
      el.style.left = `${left}px`
      el.style.top = `${top}px`
    }

    return {
      dateDom,
      datePickerDom,
      datePickerInput,
      datePickerShow,
      handleAnimationBefore,
      handleAnimationAfter,
      handleAnimationLeave
    }
  }
})
</script>
